using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using Microsoft.Win32;
using RenameX.Models;
using RenameX.Rules;
using RenameX.Services;

namespace RenameX.ViewModels
{
    public class MainViewModel : INotifyPropertyChanged
    {
        public ObservableCollection<FileItem> FileList { get; } = new();

        public ObservableCollection<IRenameRule> Rules { get; } = new();

        private IRenameRule? _selectedRule;
        public IRenameRule? SelectedRule
        {
            get => _selectedRule;
            set { if (_selectedRule != value) { _selectedRule = value; OnPropertyChanged(); } }
        }

        private readonly RenameService _renameService = new();
        private System.Threading.Timer? _previewUpdateTimer;

        public ICommand AddFilesCommand { get; }
        public ICommand AddFolderCommand { get; }
        public ICommand ExecuteCommand { get; }
        public ICommand UndoCommand { get; }
        public ICommand ClearCommand { get; }
        public ICommand RemoveSelectedCommand { get; }

        private string _filterPattern = "*.*"; // e.g. *.jpg;*.png
        public string FilterPattern
        {
            get => _filterPattern;
            set { if (_filterPattern != value) { _filterPattern = value; OnPropertyChanged(); } }
        }

        public MainViewModel()
        {
            Rules.Add(new ReplaceRule());
            Rules.Add(new AddPrefixRule());
            Rules.Add(new AddSuffixRule());
            Rules.Add(new CaseTransformRule());
            Rules.Add(new DeleteCharsRule());
            Rules.Add(new ExtensionChangeRule());
            Rules.Add(new DateTimeRule());
            Rules.Add(new SequenceRule { Format = " ({0})" });

            AddFilesCommand = new RelayCommand(AddFiles);
            ExecuteCommand = new RelayCommand(async _ => await ExecuteAsync(), _ => FileList.Any());
            UndoCommand = new RelayCommand(async _ => await UndoAsync());
            ClearCommand = new RelayCommand(ClearFiles, _ => FileList.Any());
            AddFolderCommand = new RelayCommand(AddFolder);
            RemoveSelectedCommand = new RelayCommand(_ => RemoveSelected(), _ => FileList.Any(f => f.IsSelected));

            foreach (var rule in Rules)
            {
                if (rule is INotifyPropertyChanged npc)
                {
                    npc.PropertyChanged += (_, __) => DebouncedUpdatePreview();
                }
            }
        }

        private void AddFiles()
        {
            var dlg = new Microsoft.Win32.OpenFileDialog
            {
                Multiselect = true,
                Title = "选择文件"
            };
            if (dlg.ShowDialog() == true)
            {
                AddPaths(dlg.FileNames);
                UpdatePreview();
            }
        }

        private void AddFolder()
        {
            using var dialog = new System.Windows.Forms.FolderBrowserDialog
            {
                Description = "选择文件夹",
                ShowNewFolderButton = false
            };
            var result = dialog.ShowDialog();
            if (result == System.Windows.Forms.DialogResult.OK)
            {
                var dir = dialog.SelectedPath;
                var paths = EnumerateFilesWithFilter(dir, FilterPattern);
                AddPaths(paths);
                UpdatePreview();
            }
        }

        private static string[] EnumerateFilesWithFilter(string directory, string pattern)
        {
            if (string.IsNullOrWhiteSpace(pattern)) pattern = "*.*";
            var parts = pattern.Split(';').Select(p => p.Trim()).Where(p => !string.IsNullOrEmpty(p)).ToArray();
            if (parts.Length == 0) parts = new[] { "*.*" };
            var all = parts.SelectMany(p => Directory.EnumerateFiles(directory, p, SearchOption.TopDirectoryOnly)).Distinct().ToArray();
            return all;
        }

        private void AddPaths(IEnumerable<string> paths)
        {
            foreach (var path in paths)
            {
                if (File.Exists(path))
                {
                    var name = Path.GetFileNameWithoutExtension(path);
                    FileList.Add(new FileItem
                    {
                        OriginalPath = path,
                        OriginalName = name,
                        NewName = name,
                        IsSelected = true
                    });
                }
                else if (Directory.Exists(path))
                {
                    var files = EnumerateFilesWithFilter(path, FilterPattern);
                    AddPaths(files);
                }
            }
        }

        public void AddDroppedPaths(IEnumerable<string> paths)
        {
            AddPaths(paths);
            UpdatePreview();
        }

        private void RemoveSelected()
        {
            var items = FileList.Where(f => f.IsSelected).ToList();
            foreach (var it in items) FileList.Remove(it);
        }

        private async Task ExecuteAsync()
        {
            if (!await _renameService.PrecheckAsync(FileList))
            {
                System.Windows.MessageBox.Show("存在命名冲突或目标不可写，请检查预览项。", "预检失败", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Warning);
                return;
            }
            var ok = await _renameService.ExecuteAsync(FileList);
            if (!ok)
            {
                System.Windows.MessageBox.Show("重命名过程中发生错误，已尝试回滚。", "错误", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error);
            }
            else
            {
                // 重命名成功后，更新FileItem的路径信息
                foreach (var item in FileList)
                {
                    var dir = Path.GetDirectoryName(item.OriginalPath) ?? string.Empty;
                    var newPath = Path.Combine(dir, item.NewName + (string.IsNullOrEmpty(item.NewExtension) ? string.Empty : "." + item.NewExtension));
                    item.OriginalPath = newPath;
                    item.OriginalName = item.NewName;
                }
            }
            UpdatePreview();
        }

        private async Task UndoAsync()
        {
            var ok = await _renameService.UndoAsync();
            if (ok)
            {
                // 撤销成功后，需要重新加载文件列表以获取正确的路径信息
                var currentPaths = FileList.Select(f => f.OriginalPath).ToList();
                FileList.Clear();
                
                foreach (var path in currentPaths)
                {
                    if (File.Exists(path))
                    {
                        var name = Path.GetFileNameWithoutExtension(path);
                        FileList.Add(new FileItem
                        {
                            OriginalPath = path,
                            OriginalName = name,
                            NewName = name,
                            IsSelected = true
                        });
                    }
                }
                UpdatePreview();
            }
        }

        private void ClearFiles(object? _)
        {
            FileList.Clear();
        }

        private void DebouncedUpdatePreview()
        {
            // 使用更简单的方式，避免复杂的Timer和Cancellation
            _previewUpdateTimer?.Dispose();
            _previewUpdateTimer = new System.Threading.Timer(_ => 
            {
                _previewUpdateTimer?.Dispose();
                _previewUpdateTimer = null;
                
                // 直接在主线程执行，但使用低优先级
                System.Windows.Application.Current.Dispatcher.BeginInvoke(
                    new Action(() => UpdatePreviewSync()), 
                    System.Windows.Threading.DispatcherPriority.Background);
            }, null, 100, Timeout.Infinite);
        }


        private void UpdatePreviewSync()
        {
            try
            {
                if (FileList.Count == 0) return;

                // 重置序列化规则
                foreach (var rule in Rules.OfType<SequenceRule>())
                {
                    rule.Reset();
                }

                var enabledRules = Rules.OfType<RuleBase>().Where(r => r.IsEnabled).ToList();
                var extRule = Rules.OfType<ExtensionChangeRule>().FirstOrDefault();

                // 批量更新，减少UI刷新次数
                var updates = new List<(FileItem item, string newName, string newExtension)>();

                foreach (var item in FileList)
                {
                    var name = item.OriginalName;
                    foreach (var rule in enabledRules)
                    {
                        name = rule.Apply(name);
                    }
                    
                    var newExtension = extRule != null && !string.IsNullOrWhiteSpace(extRule.NewExtension)
                        ? extRule.NewExtension.TrimStart('.')
                        : Path.GetExtension(item.OriginalPath).TrimStart('.');
                    
                    updates.Add((item, name, newExtension));
                }

                // 批量应用更新
                foreach (var (item, newName, newExtension) in updates)
                {
                    item.NewName = newName;
                    item.NewExtension = newExtension;
                }

                // 简化的冲突检测
                var targetPaths = updates.ToDictionary(
                    u => u.item, 
                    u => Path.Combine(Path.GetDirectoryName(u.item.OriginalPath) ?? string.Empty, u.newName + (string.IsNullOrEmpty(u.newExtension) ? string.Empty : "." + u.newExtension))
                );

                // 检测重复
                var duplicates = targetPaths.Values
                    .GroupBy(p => p, System.StringComparer.OrdinalIgnoreCase)
                    .Where(g => g.Count() > 1)
                    .SelectMany(g => g)
                    .ToHashSet(System.StringComparer.OrdinalIgnoreCase);

                // 应用冲突标记
                foreach (var item in FileList)
                {
                    var target = targetPaths[item];
                    item.IsConflict = duplicates.Contains(target);
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"Preview update error: {ex.Message}");
            }
        }

        public void UpdatePreview()
        {
            UpdatePreviewSync();
        }

        public event PropertyChangedEventHandler? PropertyChanged;
        protected void OnPropertyChanged([CallerMemberName] string? propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        ~MainViewModel()
        {
            _previewUpdateTimer?.Dispose();
        }
    }
}


